﻿using System;
using System.Collections.Generic;

namespace DbMetadata.Providers.SqlServer
{
    /// <summary>
    /// A type mapper that maps a data type as described my the metadata to a native .Net type.
    /// </summary>
    public class SqlTypeMapper : ITypeMapper
    {
        private readonly IDictionary<string, Type> _typeMap = new Dictionary<string, Type>();


        /// <summary>
        /// Initializes a new instance of the <see cref="SqlTypeMapper"/> class.
        /// </summary>
        public SqlTypeMapper()
        {
            CreateTypeMap();
        }

        /// <summary>
        /// Maps an external type description to a .Net type. 
        /// </summary>
        /// <param name="dataType">The data type as described by the database metadata.</param>
        /// <param name="isNullable">True is the data type should be treated as nullable, otherwise False.</param>
        /// <returns></returns>
        public virtual Type MapType(string dataType, bool isNullable)
        {
            string typeKey;

            if (isNullable)
                typeKey = string.Format("nullable {0}", dataType);
            else
                typeKey = dataType;

            if (_typeMap.ContainsKey(typeKey))
                return _typeMap[typeKey];

            //No type found, return the default
            return typeof(object);
        }

        private void CreateTypeMap()
        {
            _typeMap["nvarchar"] = typeof(string);
            _typeMap["nullable nvarchar"] = typeof(string);
            _typeMap["varchar"] = typeof(string);
            _typeMap["nullable varchar"] = typeof(string);
            _typeMap["char"] = typeof(string);
            _typeMap["nullable char"] = typeof(string);
            _typeMap["nchar"] = typeof(string);
            _typeMap["nullable nchar"] = typeof(string);
            _typeMap["datetime"] = typeof(DateTime);
            _typeMap["nullable datetime"] = typeof(DateTime?);
            _typeMap["bigint"] = typeof(long);
            _typeMap["nullable bigint"] = typeof(long?);
            _typeMap["binary"] = typeof(byte[]);
            _typeMap["nullable binary"] = typeof(byte?[]);
            _typeMap["bit"] = typeof(bool);
            _typeMap["nullable bit"] = typeof(bool?);
            _typeMap["decimal"] = typeof(decimal);
            _typeMap["nullable decimal"] = typeof(decimal?);
            _typeMap["float"] = typeof(double);
            _typeMap["nullable float"] = typeof(double?);
            _typeMap["image"] = typeof(byte[]);
            _typeMap["nullable image"] = typeof(byte[]);
            _typeMap["int"] = typeof(int);
            _typeMap["nullable int"] = typeof(int?);
            _typeMap["tinyint"] = typeof(byte);
            _typeMap["nullable tinyint"] = typeof(byte?);
            _typeMap["money"] = typeof(decimal);
            _typeMap["nullable money"] = typeof(decimal?);
            _typeMap["real"] = typeof(Single);
            _typeMap["nullable real"] = typeof(Single?);
            _typeMap["nullable uniqueidentifier"] = typeof(Guid?);
            _typeMap["uniqueidentifier"] = typeof(Guid);
            _typeMap["smalldatetime"] = typeof(DateTime);
            _typeMap["nullable smalldatetime"] = typeof(DateTime?);
            _typeMap["smallint"] = typeof(short);
            _typeMap["nullable smallint"] = typeof(short?);
            _typeMap["smallmoney"] = typeof(decimal);
            _typeMap["nullable smallmoney"] = typeof(decimal?);
            _typeMap["text"] = typeof(string);
            _typeMap["nullable text"] = typeof(string);
            _typeMap["ntext"] = typeof(string);
            _typeMap["nullable ntext"] = typeof(string);
            _typeMap["smallmoney"] = typeof(decimal);
            _typeMap["xml"] = typeof(string);
            _typeMap["numeric"] = typeof(decimal);
            _typeMap["nullable numeric"] = typeof(decimal?);
        }
    }  
}
